package com.example.hook.bytebuddy;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import net.bytebuddy.matcher.ElementMatchers;

import java.util.concurrent.Callable;

/**
 * ByteBuddy Hook 实现
 * 
 * ByteBuddy是一个强大的Java字节码生成和操作库
 * 它可以在运行时动态修改类的行为
 */
public class ByteBuddyHook {
    
    /**
     * 初始化ByteBuddy Hook
     */
    public static void initHook() {
        // 安装ByteBuddy Agent
        ByteBuddyAgent.install();
        
        try {
            // 使用ByteBuddy重新定义TargetService类
            new ByteBuddy()
                    .redefine(Class.forName("com.example.target.TargetService"))
                    // Hook add方法
                    .method(ElementMatchers.named("add"))
                    .intercept(MethodDelegation.to(AddMethodInterceptor.class))
                    // Hook getUserInfo方法
                    .method(ElementMatchers.named("getUserInfo"))
                    .intercept(MethodDelegation.to(GetUserInfoInterceptor.class))
                    // Hook静态方法formatMessage
                    .method(ElementMatchers.named("formatMessage"))
                    .intercept(MethodDelegation.to(FormatMessageInterceptor.class))
                    .make()
                    .load(Class.forName("com.example.target.TargetService").getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
            
            System.out.println("[ByteBuddy] Hook 已安装完成");
            
        } catch (Exception e) {
            System.err.println("ByteBuddy Hook 安装失败: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    /**
     * add方法的拦截器 - 使用最简单的委托方式
     */
    public static class AddMethodInterceptor {
        
        @RuntimeType
        public static Object intercept(@SuperCall Callable<?> originalMethod) throws Exception {
            
            System.out.println("[ByteBuddy Hook] add方法被调用");
            
            // 调用原始方法
            Object result = originalMethod.call();
            
            System.out.println("[ByteBuddy Hook] add原返回值: " + result);
            
            // 修改返回值：将结果乘以100
            if (result instanceof Integer) {
                int modifiedResult = ((Integer) result) * 100;
                System.out.println("[ByteBuddy Hook] add修改后返回值: " + modifiedResult);
                return modifiedResult;
            }
            
            return result;
        }
    }
    
    /**
     * getUserInfo方法的拦截器
     */
    public static class GetUserInfoInterceptor {
        
        @RuntimeType
        public static Object intercept(@SuperCall Callable<?> originalMethod) throws Exception {
            
            System.out.println("[ByteBuddy Hook] getUserInfo方法被调用");
            
            // 调用原始方法
            Object result = originalMethod.call();
            
            System.out.println("[ByteBuddy Hook] getUserInfo原返回值: " + result);
            
            // 修改返回值：添加前缀
            String modifiedResult = "[ByteBuddy_Modified] " + result;
            System.out.println("[ByteBuddy Hook] getUserInfo修改后返回值: " + modifiedResult);
            
            return modifiedResult;
        }
    }
    
    /**
     * formatMessage静态方法的拦截器
     */
    public static class FormatMessageInterceptor {
        
        @RuntimeType
        public static Object intercept(@SuperCall Callable<?> originalMethod) throws Exception {
            
            System.out.println("[ByteBuddy Hook] formatMessage静态方法被调用");
            
            // 调用原始方法
            Object result = originalMethod.call();
            
            System.out.println("[ByteBuddy Hook] formatMessage原返回值: " + result);
            
            // 修改返回值：替换格式
            String modifiedResult = "[BYTEBUDDY_FORMAT] " + result;
            System.out.println("[ByteBuddy Hook] formatMessage修改后返回值: " + modifiedResult);
            
            return modifiedResult;
        }
    }
}